package field;


import geom.Geom;
import geom.Line;
import geom.PolarVector;
import geom.Segment;
import geom.Vector;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;

import processing.core.PApplet;
import util.Prob;



public class AngleField{
	ArrayList<Line> lines;
	ArrayList<Segment> segments;
	boolean buffered = false;
	ArrayList<ArrayList<Vector>> buffer;
	private ArrayList<BinGrid> binLayers;
	private Vector size;
	Vector screenSize;
	private Vector offset;
	private Vector binSize;
	public AngleField(Vector screenSize){
		lines = new ArrayList<Line>();
		this.screenSize = screenSize;
		
		float circle = screenSize.absLength() * 1.2f;
		this.setSize(new Vector(circle, circle, 0));
		Vector numBins = new Vector(4, 4, 1);
		setBinSize(size.div(numBins));
		segments = new ArrayList<Segment>();
		setOffset(size.sub(screenSize).div(-2f));
		setBinLayers(new ArrayList<BinGrid>());
		getBinLayers().add(new BinGrid(getOffset(), size, numBins));
		getBinLayers().add(new BinGrid(getBinSize().div(-2f).add(getOffset()), size.add(getBinSize()), numBins.add(new Vector(1,1,0))));
	}
	public AngleField(Vector size, ArrayList<Line> lines){
		this(size);
		this.lines.addAll(lines);
	}
	
	public void add(Segment segment){
		PApplet.println("segment added" + segments.size()+1);
		Iterator<BinGrid> it = getBinLayers().iterator();
		while(it.hasNext()){ it.next().add(segment); }
		segments.add(segment);
	}
	
	public Bin getBin(Vector v, int layer){
		return getBinLayers().get(layer).getBinFor(v);
		
	}
	
	public ArrayList<Segment> getAllSegments(){
		return segments;
	}

	public Vector getFieldValue(FieldInterpreter fi){
		Iterator<BinGrid> it = getBinLayers().iterator();
		Vector fieldValue = new Vector();
		
		while(it.hasNext()){
			Bin bin = it.next().getBinFor(fi.getPos());
			if(bin != null){
				ArrayList<Segment> segments = bin.getContained();
				Iterator<Segment> sit = segments.iterator();
				Vector v = fi.preProcess(segments);
				while(sit.hasNext()){
					v = v.add(fi.process(sit.next(), segments));
				}
				
			fieldValue = fieldValue.add(fi.postProcess(v, segments).mult(bin.fit(v)));
			}
		}
		return fieldValue;
	}
	
	
	public ArrayList<Segment> getSegments(Vector v){
		if(getBinLayers().size() == 0) return new ArrayList<Segment>();
		Iterator<BinGrid> it = getBinLayers().iterator();
		
		ArrayList<Segment> segments = new ArrayList<Segment>();
		while(it.hasNext()){ 
			Bin b = it.next().getBinFor(v);
			
			if(b != null){
				segments.addAll(b.getContained());
			}
		}
		HashSet<Segment> set = new HashSet<Segment>(segments);
		segments.clear();
		segments.addAll(set);
		return segments;
	}

	public ArrayList<Segment> getSegments(){
		return segments;
	}
	
	public int totalSize(){
		Iterator<Line> it = lines.iterator();
		int count = 0;
		while(it.hasNext()){
			count = count + it.next().getSegments().size();
		}
		return count;
	}
	/*
	public ArrayList<Segment> getSegments(Vector v, int dist, Object self){
		ArrayList<Segment> pre = new ArrayList<Segment>();
		Iterator<Line> il = lines.iterator();
		while(il.hasNext()){
			Line line = il.next();
			if(!line.parent.equals(self)){
				Iterator<Segment> its = line.segments.iterator();
				while(its.hasNext()){
					Segment next = its.next();
					if(next.startPos().manhattanDistance(v) < dist || next.endPos().manhattanDistance(v) < dist){
						pre.add(next);
					}
				}
			}
		}
		return pre;
	}
	*/
	public void draw(PApplet pa){
		pa.noFill();
		pa.stroke(230, 100, 20, 100);
		binLayers.get(0).draw(pa);
		pa.stroke(20, 230, 230, 100);
		binLayers.get(1).draw(pa);
	}
	/*
	public Prob<Vector> getProbabilities(Vector v, Object self){
		ArrayList<Segment> pre = getSegments(v);
		Iterator<Segment> il = pre.iterator();
		Prob<Vector> probs = new Prob<Vector>();
		while(il.hasNext()){
			Segment next = il.next();
			if(!next.getParent().getParent().equals(self)){
				float dist = Geom.getDistanceFromPointToLineXY(next.startPos(), next.endPos(), v);
				//probs.add(next.relative().normalize(), sigE(dist, 640f));
			}
		}
		return probs;
	}
	*/
	public void setSize(Vector size) {
		this.size = size;
	}
	public Vector getSize() {
		return size;
	}
	public void setOffset(Vector offset) {
		this.offset = offset;
	}
	public Vector getOffset() {
		return offset;
	}
	public void setBinLayers(ArrayList<BinGrid> binLayers) {
		this.binLayers = binLayers;
	}
	public ArrayList<BinGrid> getBinLayers() {
		return binLayers;
	}
	public void setBinSize(Vector binSize) {
		this.binSize = binSize;
	}
	public Vector getBinSize() {
		return binSize;
	}
	
	/*public void draw(PApplet pa, float w, float h, float step){
		int wsteps = Math.round(w / step);
		int hsteps = Math.round(h / step);
		for(int x = 0; x < wsteps; x++){
			for(int y = 0; y < hsteps; y++){
				Vector pos = new Vector(x*step, y*step);
				Vector end = value(pos, null).mult(3).add(pos);
				pa.line(pos.x, pos.y, end.x, end.y);
			}
		}
	}*/
	

	
	

}
